﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;

namespace RestService
{
    public class CalculateDistince
    {
        public static double CalMinDisctice1PointToPolygon(List<PointF> polygon, PointF currentPoint)
        {
            try
            {
                double mind = double.MaxValue;

                if (CheckInsideOrOusidePolygon(polygon, currentPoint)) //Bên trong đa giác
                {
                    return -1;
                }
                else
                {
                    //Ngoài đa giác thì xét từng đoạn thẳng của đa giác. Lấy min là xong
                    //1 đa giác có nhiều điểm góc, nhưng thứ tự các điểm sẽ lần lượt điểm 1234 thì có cạnh 12, 23, 34. 
                    //Thực tế thuật toán có thể xử lý tổ hợp các đường thẳng, VD12,13,14,21,22,24, ... từ tập hợp điểm, nhưng k cần thiết
                    for (int i = 0; i < polygon.Count; i++)
                    {
                        //tránh so sánh ngoài list polygon
                        if (i + 1 != polygon.Count)
                        {
                            PointF startLine = polygon[i];
                            PointF endLine = polygon[i + 1];
                            double d = shortestDistance(startLine, endLine, currentPoint);
                            if (d < mind) mind = d;
                        }
                    }

                }

                return mind;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        //Khoảng cách từ 1 điểm đến 1 đoạn thẳng. Tested OK
        private static double shortestDistance(PointF startLine, PointF endLine, PointF currentPoint)
        {
            float x1 = startLine.X;
            float y1 = startLine.Y;
            float x2 = endLine.X;
            float y2 = endLine.Y;
            float x3 = currentPoint.X;
            float y3 = currentPoint.Y;

            float px = x2 - x1;
            float py = y2 - y1;
            float temp = (px * px) + (py * py);
            float u = ((x3 - x1) * px + (y3 - y1) * py) / (temp);
            if (u > 1)
            {
                u = 1;
            }
            else if (u < 0)
            {
                u = 0;
            }
            float x = x1 + u * px;
            float y = y1 + u * py;

            float dx = x - x3;
            float dy = y - y3;
            double dist = Math.Sqrt(dx * dx + dy * dy);
            return dist;
        }

        //kiếm tra xem 1 điểm nằm trong hay ngoài đa giác.
        //Thuật toán này yêu cầu điểm đầu trong đa giác là điểm cuối
        private static bool CheckInsideOrOusidePolygon(List<PointF> polygon, PointF currentPoint)
        {
            try
            {
                //Ray-cast algorithm is here onward
                int k, j = polygon.Count - 1;
                bool oddNodes = false; //to check whether number of intersections is odd
                for (k = 0; k < polygon.Count; k++)
                {
                    //fetch adjucent points of the polygon
                    PointF polyK = polygon[k];
                    PointF polyJ = polygon[j];

                    //check the intersections
                    if (((polyK.Y > currentPoint.Y) != (polyJ.Y > currentPoint.Y)) &&
                     (currentPoint.X < (polyJ.X - polyK.X) * (currentPoint.Y - polyK.Y) / (polyJ.Y - polyK.Y) + polyK.X))
                        oddNodes = !oddNodes; //switch between odd and even
                    j = k;
                }

                if (oddNodes)
                {
                    //inside
                    return true;
                }
                else
                {
                    //outside
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
    }
}